<?php

namespace EchoPHP\Foundation\Http;

use EchoPHP\Facades\Facade;
use EchoPHP\Foundation\Application;
use EchoPHP\Foundation\Exception\Handler as ExceptionHandler;
use EchoPHP\Http\Middleware\EnableCrossMiddle;
use EchoPHP\Http\Middleware\TrustProxies;
use EchoPHP\Pipeline\Pipeline;
use EchoPHP\Route\Router;
use Exception;

class Kernel {
    /**
     * 应用程序实例
     * @var \EchoPHP\Foundation\Application
     */
    protected $app;

    /**
     * 路由实例
     * @var \EchoPHP\Route\Router
     */
    protected $router;

    /**
     * 应用程序执行的中间件
     * @var array
     */
    protected $middleware = [
        EnableCrossMiddle::class,
        TrustProxies::class
    ];

    /**
     * 应用程序启动执行类
     * @var array
     */
    protected $bootstrappers = [
        \EchoPHP\Foundation\BootStrap\LoadAppEnvironment::class,
        \EchoPHP\Foundation\BootStrap\LoadConfiguration::class,
        \EchoPHP\Foundation\BootStrap\HandleException::class,
        \EchoPHP\Foundation\BootStrap\HandleSession::class,
        \EchoPHP\Foundation\BootStrap\RegisterFacades::class,
        \EchoPHP\Foundation\BootStrap\RegisterProviders::class,
        \EchoPHP\Foundation\BootStrap\BootProviders::class,
        \EchoPHP\Foundation\BootStrap\RegisterGlobalRequestTrim::class
    ];

    /**
     * 实例化内核程序
     * @param Application $app
     * @param Router $router
     */
    public function __construct(Application $app, Router $router) {
        $this->app = $app;
        $this->router = $router;
    }

    /**
     * 内核处理程序
     * @param $request
     * @return mixed|void
     */
    public function handle($request) {
        try {
            $response = $this->sendRequestFromRouter($request);
        } catch (Exception $e) {
            $this->reportException($e);

            $response = $this->renderException($request, $e);
        }

        return $response;
    }

    /**
     * 通过路由发送http请求
     * @param $request
     * @return mixed
     * @throws Exception
     */
    protected function sendRequestFromRouter($request) {
        $this->app->instance('request', $request);
        Facade::clearBuiltFacadeInstance('request');

        $this->bootstrap();
        return (new Pipeline($this->app))
            ->send($request)
            ->through($this->middleware)
            ->then($this->dispatchToRouter());
    }

    /**
     * 初始化应用程序
     * @throws Exception
     */
    protected function bootstrap() {
        if (!$this->app->hasBeenBootstrapped()) {
            $this->app->bootstrapWith($this->bootstrappers);
        }
    }

    /**
     * 将请求派发到路由地址中
     * @return \Closure
     */
    protected function dispatchToRouter() {
        return function ($request) {
            return $this->router->runRoute($request);
        };
    }

    /**
     * 报告异常信息
     * @param Exception $e
     */
    protected function reportException(Exception $e) {
        $this->app[ExceptionHandler::class]->report($e);
    }

    /**
     * 渲染输出异常信息
     * @param $request
     * @param Exception $e
     * @return
     */
    protected function renderException($request, Exception $e) {
        return $this->app[ExceptionHandler::class]->render($request, $e);
    }
}